home *** CD-ROM | disk | FTP | other *** search
- /* pl-file.c,v 1.22 1994/04/11 08:37:36 jan Exp
-
- Copyright (c) 1990 Jan Wielemaker. All rights reserved.
- See ../LICENCE to find out about your rights.
- jan@swi.psy.uva.nl
-
- Purpose: file system i/o
- */
-
- /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- This module is far too big. It defines a layer around open(), etc. to
- get opening and closing of files to the symbolic level required for
- Prolog. It also defines basic I/O predicates, stream based I/O and
- finally a bundle of operations on files, such as name expansion,
- renaming, deleting, etc. Most of this module is rather straightforward.
-
- If time is there I will have a look at all this to clean it. Notably
- handling times must be cleaned, but that not only holds for this module.
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
-
- #if defined(__WINDOWS__) || defined(__NT__)
- #include "windows.h"
- #undef FD_SET
- #undef FD_ISSET
- #undef FD_ZERO
- #endif
-
- #include "pl-incl.h"
- #include "pl-ctype.h"
- #ifdef __WIN32__
- #include <console.h>
- #endif
-
- #ifdef HAVE_SYS_PARAM_H
- #include <sys/param.h>
- #endif
- #ifdef HAVE_SYS_FILE_H
- #include <sys/file.h>
- #endif
- #ifdef HAVE_UNISTD_H
- #include <unistd.h>
- #endif
- #ifdef HAVE_BSTRING_H
- #include <bstring.h>
- #endif
-
- #define ST_TERMINAL 0 /* terminal based stream */
- #define ST_FILE 1 /* File bound stream */
- #define ST_PIPE 2 /* Pipe bound stream */
- #define ST_STRING 3 /* String bound stream */
-
- /* openStream() flags */
- #define OPEN_OPEN 0x1 /* Open for open/[3,4] */
- #define OPEN_TEXT 0x2 /* Open in text-mode */
-
- typedef struct plfile * PlFile;
-
- static struct plfile
- { atom_t name; /* name of file */
- atom_t stream_name; /* stream identifier name */
- IOSTREAM * stream; /* IOSTREAM package descriptor */
- char status; /* F_CLOSED, F_READ, F_WRITE */
- char type; /* ST_FILE, ST_PIPE, ST_STRING */
- } *fileTable = (PlFile) NULL; /* Our file table */
-
- int Input; /* current input */
- int Output; /* current output */
-
- ttybuf ttytab; /* saved terminal status on entry */
- int ttymode; /* Current tty mode */
-
- static atom_t prompt_atom; /* current prompt */
- static char *first_prompt; /* First-line prompt */
- static int first_prompt_used; /* flag */
- static int protocolStream = -1; /* doing protocolling on stream <n> */
-
- static int maxfiles; /* maximum file index */
-
- typedef struct input_context * InputContext;
- typedef struct output_context * OutputContext;
-
- static struct input_context
- { int stream; /* pushed input */
- atom_t term_file; /* old term_position file */
- int term_line; /* old term_position line */
- InputContext previous; /* previous context */
- } *input_context_stack = NULL;
-
- static struct output_context
- { int stream; /* pushed input */
- OutputContext previous; /* previous context */
- } *output_context_stack = NULL;
-
- forwards bool openStream(term_t file, int mode, int flags);
- forwards bool closeStream(int);
- forwards bool unifyStreamName(term_t, int);
- forwards bool unifyStreamNo(term_t, int);
- forwards bool setUnifyStreamNo(term_t, int);
- forwards bool unifyStreamMode(term_t, int);
- forwards int Get0();
-
- static jmp_buf pipe_context; /* jmp buffer for pipe operations */
- static int inpipe; /* doing a pipe operation */
-
-
- #ifdef SIGPIPE
- static void
- pipeHandler(int sig)
- { if ( inpipe )
- { longjmp(pipe_context, 1);
- }
-
- warning("Broken pipe\n"); /* Unexpected broken pipe */
- pl_abort();
-
- signal(SIGPIPE, SIG_DFL); /* should abort fail. */
- kill(getpid(), SIGPIPE); /* Unix has both pipes and kill() */
- }
- #endif /* SIGPIPE */
-
- static void
- brokenPipe(int n, atom_t rw)
- { term_t stream = PL_new_term_ref();
- unifyStreamNo(stream, n);
- if ( rw == ATOM_write && n == Output )
- Output = 1;
- PL_error(NULL, 0, "Broken pipe", ERR_STREAM_OP, rw, stream);
- }
-
- #define TRYPIPE(no, rw, code, err) \
- if ( fileTable[(no)].type == ST_PIPE ) \
- { if ( setjmp(pipe_context) != 0 ) \
- { inpipe--; \
- brokenPipe(no, rw); \
- err; \
- } else \
- { inpipe++; \
- code; \
- inpipe--; \
- } \
- } else \
- { code; \
- }
-
-
- void
- initIO(void)
- { int n;
-
- fileerrors = TRUE;
- if ( maxfiles != getdtablesize() )
- { if ( fileTable != (PlFile) NULL )
- freeHeap(fileTable, sizeof(struct plfile) * maxfiles);
- maxfiles = getdtablesize();
- fileTable = allocHeap(sizeof(struct plfile) * maxfiles);
- }
-
- #ifdef __unix__
- if ( !isatty(0) || !isatty(1) ) /* Sinput is not a tty */
- GD->cmdline.notty = TRUE;
- #endif
-
- /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- Initilise user input, output and error stream. How to do this neatly
- without the Unix assumptions?
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
-
- for(n=0; n<maxfiles; n++)
- { PlFile f = &fileTable[n];
-
- switch(n)
- { case 0:
- f->name = ATOM_user;
- f->stream_name = ATOM_user_input;
- f->stream = Sinput;
- f->status = F_READ;
- f->type = ST_TERMINAL;
- break;
- case 1:
- f->name = ATOM_user;
- f->stream_name = ATOM_user_output;
- f->stream = Soutput;
- f->status = F_WRITE;
- f->type = ST_TERMINAL;
- break;
- case 2:
- f->name = ATOM_stderr;
- f->stream_name = ATOM_user_error;
- f->stream = Serror;
- f->status = F_WRITE;
- f->type = ST_TERMINAL;
- break;
- default:
- f->name = NULL_ATOM;
- f->stream = NULL_ATOM;
- f->type = ST_FILE;
- f->status = F_CLOSED;
- }
- }
-
- ResetTty();
- Sinput->position = &Sinput->posbuf; /* position logging */
- Soutput->position = &Sinput->posbuf;
- Serror->position = &Sinput->posbuf;
-
- ttymode = TTY_COOKED;
- PushTty(&ttytab, TTY_SAVE);
-
- Input = 0;
- Output = 1;
-
- if ( prompt_atom == NULL_ATOM )
- prompt_atom = ATOM_prompt;
- }
-
-
- void
- dieIO()
- { if ( GD->io_initialised )
- { pl_noprotocol();
- closeFiles(TRUE);
- PopTty(&ttytab);
- }
- }
-
-
- static bool
- closeStream(int n)
- { PlFile f = &fileTable[n];
-
- if ( f->stream )
- { switch(n)
- { case 0:
- Sclearerr(f->stream);
- break;
- case 1:
- case 2:
- Sflush(f->stream);
- break;
- default:
- if ( f->status == F_WRITE )
- { TRYPIPE(n, ATOM_write, Sclose(f->stream), (void)0);
- } else
- Sclose(f->stream);
- f->stream = NULL_ATOM;
- f->name = NULL_ATOM;
- f->status = F_CLOSED;
- break;
- }
- }
-
- succeed;
- }
-
-
- void
- closeFiles(int all)
- { volatile int n;
- #if O_PCE
- extern int read_nesting;
- read_nesting = 0;
- #endif
-
- for(n=0; n<maxfiles; n++)
- { IOSTREAM *s;
-
- if ( (s=fileTable[n].stream) )
- { if ( all || !(s->flags & SIO_NOCLOSE) )
- closeStream(n);
- else if ( fileTable[n].status == F_WRITE )
- { TRYPIPE(n, ATOM_write, Sflush(s), (void)0);
- }
- }
- }
-
- Input = 0;
- Output = 1;
- }
-
-
- void
- protocol(char *s, int n)
- { if ( protocolStream >= 0 )
- { int out;
-
- out = Output;
- Output = protocolStream;
- for( ; n > 0; s++, n--)
- Put((int)*s & 0xff);
- Output = out;
- }
- }
-
-
- /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- push/popInputContext() maintain the source_location info over see(X),
- ..., seen(X). This is very hairy. Note the common seeing(O), see(N),
- ..., seen, see(O) construct. To fix this one, see/1 will only push the
- context if it concerns a new stream and seen() will only pop if it is an
- open stream.
-
- Should be fixed decently if we redesign all of I/O stream management.
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
-
- static void
- pushInputContext()
- { InputContext c = allocHeap(sizeof(struct input_context));
-
- c->stream = Input;
- c->term_file = source_file_name;
- c->term_line = source_line_no;
- c->previous = input_context_stack;
- input_context_stack = c;
- }
-
-
- static void
- popInputContext()
- { InputContext c = input_context_stack;
-
- if ( c )
- { Input = c->stream;
- source_file_name = c->term_file;
- source_line_no = c->term_line;
- input_context_stack = c->previous;
- freeHeap(c, sizeof(struct input_context));
- } else
- Input = 0;
- }
-
- static void
- pushOutputContext()
- { OutputContext c = allocHeap(sizeof(struct output_context));
-
- c->stream = Output;
- c->previous = output_context_stack;
- output_context_stack = c;
- }
-
-
- static void
- popOutputContext()
- { OutputContext c = output_context_stack;
-
- if ( c )
- { Output = c->stream;
- output_context_stack = c->previous;
- freeHeap(c, sizeof(struct output_context));
- } else
- Output = 0;
- }
-
-
- int
- currentLinePosition()
- { IOSTREAM *stream = fileTable[Output].stream;
-
- if ( stream && stream->position )
- return stream->position->linepos;
-
- return 0;
- }
-
-
- /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- Get a single character from the terminal without waiting for a return.
- The character should not be echoed. If GD->cmdline.notty is true this
- function will read the first character and then skip all character upto
- and including the newline.
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
-
- int
- getSingleChar(void)
- { int c;
- int OldIn = Input;
- ttybuf buf;
- IOSTREAM *stream;
-
- Input = 0;
- stream = fileTable[Input].stream;
- debugstatus.suspendTrace++;
- pl_ttyflush();
- PushTty(&buf, TTY_RAW); /* just donot prompt */
-
- if ( GD->cmdline.notty )
- { Char c2;
-
- c2 = Get0();
- while( c2 == ' ' || c2 == '\t' ) /* skip blanks */
- c2 = Get0();
- c = c2;
- while( c2 != EOF && c2 != '\n' ) /* read upto newline */
- c2 = Get0();
- } else
- { if ( stream->position )
- { IOPOS oldpos = *stream->position;
- c = Get0();
- *stream->position = oldpos;
- } else
- c = Get0();
- }
-
- PopTty(&buf);
- debugstatus.suspendTrace--;
- Input = OldIn;
-
- return c;
- }
-
-
- word
- pl_rawtty(term_t goal)
- { bool rval;
- int OldIn = Input;
- ttybuf buf;
-
- Input = 0;
- debugstatus.suspendTrace++;
- pl_ttyflush();
- PushTty(&buf, TTY_RAW);
-
- rval = callProlog(NULL, goal, FALSE);
-
- PopTty(&buf);
- debugstatus.suspendTrace--;
-
- Input = OldIn;
-
- return rval;
- }
-
-
- #ifndef DEL
- #define DEL 127
- #endif
-
- bool
- readLine(char *buffer)
- { int oldin = Input;
- int oldout = Output;
- int c;
- char *buf = &buffer[strlen(buffer)];
- ttybuf tbuf;
-
- Input = 0;
- Output = 1;
- if ( !GD->cmdline.notty )
- PushTty(&tbuf, TTY_RAW); /* just donot prompt */
-
- for(;;)
- { pl_flush();
-
- switch( (c=Get0()) )
- { case '\n':
- case '\r':
- case EOF:
- *buf++ = EOS;
- Input = oldin;
- Output = oldout;
- if ( !GD->cmdline.notty )
- PopTty(&tbuf);
-
- return c == EOF ? FALSE : TRUE;
- case '\b':
- case DEL:
- if ( !GD->cmdline.notty && buf > buffer )
- { Putf("\b \b");
- buf--;
- }
- default:
- if ( !GD->cmdline.notty )
- Put(c);
- *buf++ = c;
- }
- }
- }
-
-
- bool
- LockStream()
- { IOSTREAM *s = fileTable[Output].stream;
-
- return (s && Slock(s) < 0) ? FALSE : TRUE;
- }
-
-
- bool
- UnlockStream()
- { IOSTREAM *s = fileTable[Output].stream;
-
- return (s && Sunlock(s) < 0) ? FALSE : TRUE;
- }
-
-
- bool
- Put(int c)
- { IOSTREAM *s = fileTable[Output].stream;
- int rval;
-
- if ( !s )
- fail;
-
- TRYPIPE(Output, ATOM_write, rval = Sputc(c, s), rval = -1);
-
- return rval < 0 ? FALSE : TRUE;
- }
-
-
- /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- PutOpenToken() inserts a space in the output stream if the last-written
- and given character require a space to ensure a token-break.
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
-
- bool
- PutOpenToken(int c)
- { IOSTREAM *s = fileTable[Output].stream;
-
- if ( c == EOF )
- { s->lastc = EOF;
- succeed;
- }
-
- if ( s->lastc != EOF &&
- ((isAlpha(s->lastc) && isAlpha(c)) ||
- (isSymbol(s->lastc) && isSymbol(c)) ||
- c == '(') )
- return Put(' ');
-
- succeed;
- }
-
-
- bool
- Puts(const char *str)
- { IOSTREAM *s = fileTable[Output].stream;
- int rval;
-
- if ( !s )
- fail;
-
- TRYPIPE(Output, ATOM_write, rval = Sfputs(str, s), rval = -1);
-
- return rval < 0 ? FALSE : TRUE;
- }
-
-
- word
- Putf(char *fm, ...)
- { IOSTREAM *s = fileTable[Output].stream;
- va_list args;
- int rval;
-
- if ( !s )
- fail;
-
- va_start(args, fm);
- TRYPIPE(Output, ATOM_write, rval = Svfprintf(s, fm, args), rval = -1);
- va_end(args);
-
- return rval < 0 ? FALSE : TRUE;
- }
-
-
- static int
- Get0()
- { IOSTREAM *s = fileTable[Input].stream;
- int c;
-
- if ( s )
- { TRYPIPE(Input, ATOM_read, c=Sgetc(s), c=EOF);
-
- if ( c == EOF && Sfpasteof(s) )
- { term_t stream = PL_new_term_ref();
-
- unifyStreamNo(stream, Input);
- PL_error(NULL, 0, NULL, ERR_PERMISSION,
- ATOM_input, ATOM_past_end_of_stream, stream);
- }
- } else
- c = EOF;
-
- return c;
- }
-
-
- IOSTREAM *
- PL_current_input()
- { return fileTable[Input].stream;
- }
-
-
- IOSTREAM *
- PL_current_output()
- { return fileTable[Output].stream;
- }
-
-
- word
- pl_dup_stream(term_t from, term_t to)
- { int fn, tn;
- PlFile f, t;
-
- if ( (fn = streamNo(from, F_ANY)) < 0 ||
- (tn = streamNo(to, F_ANY)) < 0 )
- fail;
-
- f = &fileTable[fn];
- t = &fileTable[tn];
-
- t->stream = f->stream;
- t->status = f->status;
- t->type = f->type;
-
- succeed;
- }
-
-
- bool
- PL_open_stream(term_t handle, IOSTREAM *s)
- { int n;
- PlFile f;
-
- for(n=3, f=&fileTable[n]; n<maxfiles; n++, f++)
- { if ( !f->stream )
- { f->stream = s;
- f->name = NULL_ATOM;
- f->type = ST_FILE;
- if ( s->flags & SIO_INPUT )
- f->status = F_READ;
- else
- f->status = F_WRITE;
-
- return setUnifyStreamNo(handle, n);
- }
- }
-
- return PL_error(NULL, 0, NULL, ERR_REPRESENTATION, ATOM_max_files);
- }
-
-
- static bool
- openStream(term_t file, int mode, int flags)
- { int n;
- IOSTREAM *stream;
- char cmode[3];
- atom_t name;
- functor_t f;
- int type;
-
- DEBUG(2, Sdprintf("openStream file=0x%lx, mode=%d\n", file, mode));
-
- if ( PL_get_atom(file, &name) )
- { type = ST_FILE;
- } else if ( PL_get_functor(file, &f) && f == FUNCTOR_pipe1)
- {
- #ifdef SIGPIPE
- term_t an = PL_new_term_ref();
- type = ST_PIPE;
-
- if ( !PL_get_arg(1, file, an) ||
- !PL_get_atom(an, &name) )
- return PL_error(NULL, 0, NULL, ERR_DOMAIN, ATOM_source_sink, file);
-
- signal(SIGPIPE, pipeHandler);
- #else
- return PL_error(NULL, 0, NULL, ERR_NOTIMPLEMENTED, ATOM_pipe);
- #endif /*SIGPIPE*/
- } else
- return PL_error(NULL, 0, NULL, ERR_DOMAIN, ATOM_source_sink, file);
-
- DEBUG(3, Sdprintf("File/command name = %s\n", stringAtom(name)));
- if ( type == ST_FILE )
- { if ( mode == F_READ )
- { if ( name == ATOM_user || name == ATOM_user_input )
- { Input = 0;
- succeed;
- }
- } else
- { if ( name == ATOM_user || name == ATOM_user_output )
- { Output = 1;
- succeed;
- }
- if ( name == ATOM_user_error || name == ATOM_stderr )
- { Output = 2;
- succeed;
- }
- }
- } else if ( type == ST_PIPE && (mode == F_APPEND || mode == F_WRNOTRUNC) )
- { term_t tmp = PL_new_term_ref();
-
- PL_put_atom(tmp, (mode == F_APPEND ? ATOM_append : ATOM_update));
- return PL_error(NULL, 0, NULL, ERR_DOMAIN, ATOM_io_mode, tmp);
- }
-
- if ( !(flags & OPEN_OPEN) ) /* see/1, tell/1, append/1 */
- { for( n=0; n<maxfiles; n++ )
- { if ( fileTable[n].name == name && fileTable[n].type == type )
- { if ( fileTable[n].status == mode )
- { switch(mode)
- { case F_READ: Input = n; break;
- case F_WRITE:
- case F_WRNOTRUNC:
- case F_APPEND: Output = n; break;
- }
- DEBUG(3, Sdprintf("Switched back to already open stream %d\n", n));
- succeed;
- } else
- { closeStream(n);
- }
- break;
- }
- }
-
- if ( mode == F_READ )
- pushInputContext(); /* see/1 to a new file */
- }
-
- DEBUG(2, Sdprintf("Starting Unix open\n"));
- cmode[0] = FOPENMODE[mode];
- if ( flags & OPEN_TEXT )
- cmode[1] = EOS;
- else
- { cmode[1] = 'b';
- cmode[2] = EOS;
- }
-
- #ifdef HAVE_POPEN
- if ( type == ST_PIPE )
- { if ( !(stream=Sopen_pipe(stringAtom(name), cmode)) )
- goto err;
- } else
- #endif /*HAVE_POPEN*/
- { char *fn;
- char tmp[MAXPATHLEN];
-
- if ( !(fn = ExpandOneFile(stringAtom(name), tmp)) )
- fail;
-
- if ( !(stream=Sopen_file(fn, cmode)) )
- {
- #ifdef HAVE_POPEN
- err:
- #endif
- if ( fileerrors )
- { PL_error(NULL, 0, OsError(), ERR_FILE_OPERATION,
- ATOM_open, ATOM_source_sink, file);
- }
- fail;
- }
- }
-
- for(n=3; n<maxfiles; n++)
- { if ( !fileTable[n].stream )
- break;
- }
- if ( n >= maxfiles ) /* non-ISO */
- return PL_error(NULL, 0, NULL, ERR_REPRESENTATION, ATOM_max_files);
-
- fileTable[n].name = name;
- fileTable[n].stream_name = NULL_ATOM;
- fileTable[n].type = type;
- fileTable[n].stream = stream;
-
- switch(mode)
- { case F_READ:
- Input = n; break;
- case F_WRITE:
- case F_WRNOTRUNC:
- case F_APPEND:
- mode = F_WRITE;
- Output = n; break;
- }
- fileTable[n].status = mode;
-
- DEBUG(2, Sdprintf("Prolog fileTable[] updated\n"));
-
- succeed;
- }
-
-
- static bool
- unifyStreamName(term_t f, int n)
- { if ( fileTable[n].status == F_CLOSED )
- fail;
-
- if ( !(PL_is_variable(f) || PL_is_atom(f)) )
- return PL_error(NULL, 0, NULL, ERR_TYPE, ATOM_variable, f);
-
- #ifdef HAVE_POPEN
- if ( fileTable[n].type == ST_PIPE )
- { return PL_unify_term(f,
- PL_FUNCTOR, FUNCTOR_pipe1,
- PL_ATOM, fileTable[n].name);
- }
- #endif /*HAVE_POPEN*/
-
- return PL_unify_atom(f, fileTable[n].name);
- }
-
-
- static bool
- unifyStreamMode(term_t m, int n)
- { if ( fileTable[n].status == F_CLOSED )
- fail;
-
- return PL_unify_atom(m, fileTable[n].status == F_READ ? ATOM_read
- : ATOM_write);
- }
-
-
- static bool
- unifyStreamNo(term_t stream, int n)
- { atom_t name;
-
- switch( n )
- { case 0:
- name = ATOM_user_input;
- break;
- case 1:
- name = ATOM_user_output;
- break;
- case 2:
- name = ATOM_user_error;
- break;
- default:
- if ( fileTable[n].stream_name )
- name = fileTable[n].stream_name;
- return PL_unify_integer(stream, n);
- }
-
- return PL_unify_atom(stream, name);
- }
-
-
- word
- pl_told()
- { if ( fileTable[Output].status != F_WRITE )
- succeed;
-
- closeStream(Output);
-
- Output = 1;
- succeed;
- }
-
-
- word
- pl_flush()
- { IOSTREAM *s;
-
- if ( fileTable[Output].status == F_WRITE &&
- (s=fileTable[Output].stream) )
- { TRYPIPE(Output, ATOM_write, Sflush(s), fail);
- }
-
- succeed;
- }
-
-
- word
- pl_see(term_t f)
- { return openStream(f, F_READ, OPEN_TEXT);
- }
-
-
- word
- pl_seen()
- { if ( fileTable[Input].status != F_READ )
- succeed;
-
- closeStream(Input);
- popInputContext();
-
- succeed;
- }
-
-
- static word
- openProtocol(term_t f, bool appnd)
- { int out = Output;
-
- pl_noprotocol();
-
- if ( openStream(f, appnd ? F_APPEND : F_WRITE, OPEN_TEXT|OPEN_OPEN) )
- { IOSTREAM *s = fileTable[Output].stream;
-
- s->flags |= SIO_NOCLOSE;
- protocolStream = Output;
- Output = out;
-
- succeed;
- }
- Output = out;
-
- fail;
- }
-
-
- word
- pl_noprotocol()
- { if ( protocolStream >= 0 )
- { closeStream(protocolStream);
- protocolStream = -1;
- }
-
- succeed;
- }
-
-
- /********************************
- * STRING I/O *
- *********************************/
-
-
- bool
- seeString(char *s)
- { IOSTREAM *stream = Sopen_string(NULL, s, -1, "r");
- PlFile f;
- int n;
-
- for(n=3, f=&fileTable[n]; n<maxfiles; n++, f++)
- { if ( !f->stream )
- { f->stream = stream;
- f->name = NULL_ATOM;
- f->status = F_READ;
- f->type = ST_STRING;
-
- pushInputContext();
- Input = n;
- succeed;
- }
- }
-
- return PL_error(NULL, 0, NULL, ERR_REPRESENTATION, ATOM_max_files);
- }
-
-
- bool
- seeingString()
- { return fileTable[Input].type == ST_STRING;
- }
-
-
- bool
- seenString()
- { PlFile f = &fileTable[Input];
-
- if ( f->type == ST_STRING && f->stream )
- { Sclose(f->stream);
- f->stream = NULL;
- f->status = F_CLOSED;
- popInputContext();
- }
-
- succeed;
- }
-
-
- bool
- tellString(char **s, int size)
- { static int sbuf;
- IOSTREAM *stream;
- PlFile f;
- int n;
-
- sbuf = size;
- stream = Sopenmem(s, &sbuf, "w");
-
- for(n=3, f=&fileTable[n]; n<maxfiles; n++, f++)
- { if ( !f->stream )
- { f->stream = stream;
- f->name = NULL_ATOM;
- f->status = F_WRITE;
- f->type = ST_STRING;
-
- pushOutputContext();
- Output = n;
- succeed;
- }
- }
-
- return PL_error(NULL, 0, NULL, ERR_REPRESENTATION, ATOM_max_files);
- }
-
-
- bool
- toldString()
- { PlFile f = &fileTable[Output];
-
- if ( f->type == ST_STRING && f->stream )
- { Sputc(EOS, f->stream);
- Sclose(f->stream);
- f->stream = NULL;
- f->status = F_CLOSED;
- popOutputContext();
- }
-
- succeed;
- }
-
-
- /********************************
- * INPUT IOSTREAM NAME *
- *********************************/
-
- atom_t
- currentStreamName() /* only if a file! */
- { PlFile f = &fileTable[Input];
-
- if ( f->type == ST_FILE || f->type == ST_PIPE )
- return f->name;
-
- return NULL_ATOM;
- }
-
- void
- setCurrentSourceLocation()
- { PlFile f = &fileTable[Input];
-
- if ( f->type == ST_FILE || f->type == ST_PIPE )
- { IOSTREAM *stream = f->stream;
-
- source_file_name = f->name;
- if ( stream && stream->position )
- { source_line_no = stream->position->lineno;
- source_char_no = stream->position->charno - 1; /* char just read! */
- }
- } else
- { source_file_name = NULL_ATOM;
- source_line_no = -1;
- source_char_no = 0;
- }
- }
-
- /********************************
- * WAITING FOR INPUT *
- ********************************/
-
- #ifndef HAVE_SELECT
-
- word
- pl_wait_for_input(term_t streams, term_t available,
- term_t timeout)
- { return notImplemented("wait_for_input", 3);
- }
-
- #else
-
- word
- pl_wait_for_input(term_t Streams, term_t Available,
- term_t timeout)
- { fd_set fds;
- struct timeval t, *to;
- double time;
- int n, max = 0;
- char fdmap[256];
- term_t head = PL_new_term_ref();
- term_t streams = PL_copy_term_ref(Streams);
- term_t available = PL_copy_term_ref(Available);
-
- FD_ZERO(&fds);
- while( PL_get_list(streams, head, streams) )
- { IOSTREAM *s;
- int n, fd;
-
- if ( (n = streamNo(head, F_READ)) < 0 )
- fail;
- if ( !(s = fileTable[n].stream) || (fd=Sfileno(s)) < 0 )
- fail;
- fdmap[fd] = n;
-
- FD_SET(fd, &fds);
- if ( fd > max )
- max = fd;
- }
- if ( !PL_get_nil(streams) )
- return PL_error("wait_for_input", 3, NULL, ERR_TYPE, ATOM_list, Streams);
- if ( !PL_get_float(timeout, &time) )
- return PL_error("wait_for_input", 3, NULL, ERR_TYPE, ATOM_float, timeout);
-
- if ( time > 0.0 )
- { t.tv_sec = (int)time;
- t.tv_usec = ((int)(time * 1000000) % 1000000);
- to = &t;
- } else
- to = NULL;
-
- #ifdef hpux
- select(max+1, (int*) &fds, NULL, NULL, to);
- #else
- select(max+1, &fds, NULL, NULL, to);
- #endif
-
- for(n=0; n <= max; n++)
- { if ( FD_ISSET(n, &fds) )
- { if ( !PL_unify_list(available, head, available) ||
- !unifyStreamName(head, fdmap[n]) )
- fail;
- }
- }
- PL_unify_nil(available);
-
- succeed;
- }
-
- #endif /* HAVE_SELECT */
-
- /********************************
- * PROLOG CONNECTION *
- *********************************/
-
- word
- pl_put(term_t c)
- { int chr;
- char *s;
-
- if ( PL_get_integer(c, &chr) )
- { if (chr < 0 || chr > 255)
- goto err;
- Put(chr);
- } else if ( PL_get_chars(c, &s, CVT_ATOM|CVT_LIST|CVT_STRING) )
- { Puts(s);
- } else
- { err:
- return PL_error("put", 1, NULL, ERR_TYPE, ATOM_character, c);
- }
-
- succeed;
- }
-
- word
- pl_put2(term_t stream, term_t chr)
- { streamOutput(stream, pl_put(chr));
- }
-
- word
- pl_get(term_t chr)
- { int c;
-
- do
- { c = Get0();
- } while( c != EOF && isBlank(c) );
-
- return PL_unify_integer(chr, c);
- }
-
-
- word
- pl_skip(term_t chr)
- { int c;
- int r;
-
- if ( !PL_get_integer(chr, &c) || c < 0 || c > 255 )
- return PL_error("skip", 1, NULL, ERR_TYPE, ATOM_character, chr);
-
- while((r=Get0()) != c && r != EOF )
- ;
-
- succeed;
- }
-
-
- word
- pl_skip2(term_t stream, term_t chr)
- { streamInput(stream, pl_skip(chr));
- }
-
-
- word
- pl_get2(term_t stream, term_t chr)
- { streamInput(stream, pl_get(chr));
- }
-
- word
- pl_tty() /* $tty/0 */
- { if ( GD->cmdline.notty )
- fail;
- succeed;
- }
-
- word
- pl_get_single_char(term_t c)
- { return PL_unify_integer(c, getSingleChar());
- }
-
- word
- pl_get0(term_t c)
- { return PL_unify_integer(c, Get0());
- }
-
- word
- pl_get02(term_t stream, term_t c)
- { streamInput(stream, pl_get0(c))
- }
-
- word
- pl_seeing(term_t f)
- { return unifyStreamName(f, Input);
- }
-
- word
- pl_telling(term_t f)
- { return unifyStreamName(f, Output);
- }
-
- word
- pl_tell(term_t f)
- { return openStream(f, F_WRITE, OPEN_TEXT);
- }
-
- word
- pl_append(term_t f)
- { return openStream(f, F_APPEND, OPEN_TEXT);
- }
-
-
- word
- pl_ttyflush()
- { int OldOut = Output;
- bool rval;
-
- Output = 1;
- rval = pl_flush();
- Output = OldOut;
-
- return rval;
- }
-
-
- word
- pl_protocol(term_t file)
- { return openProtocol(file, FALSE);
- }
-
-
- word
- pl_protocola(term_t file)
- { return openProtocol(file, TRUE);
- }
-
-
- word
- pl_protocolling(term_t file)
- { if ( protocolStream >= 0 )
- return unifyStreamName(protocolStream, file);
-
- fail;
- }
-
-
- word
- pl_prompt(term_t old, term_t new)
- { atom_t a;
-
- if ( PL_unify_atom(old, prompt_atom) &&
- PL_get_atom(new, &a) )
- { prompt_atom = a;
- succeed;
- }
-
- fail;
- }
-
-
- void
- prompt1(char *prompt)
- { if ( first_prompt )
- remove_string(first_prompt);
- first_prompt = store_string(prompt);
- first_prompt_used = FALSE;
- }
-
-
- word
- pl_prompt1(term_t prompt)
- { char *s;
-
- if ( PL_get_chars(prompt, &s, CVT_ALL) )
- { prompt1(s);
- succeed;
- }
-
- return PL_error("prompt1", 1, NULL, ERR_TYPE, ATOM_atom, prompt);
- }
-
-
- word
- pl_tab(term_t spaces)
- { number n;
-
- if ( valueExpression(spaces, &n) &&
- toIntegerNumber(&n) )
- { int m = n.value.i;
-
- while(m-- > 0)
- Put(' ');
-
- succeed;
- }
-
- return PL_error("tab", 1, NULL, ERR_TYPE, ATOM_integer, spaces);
- }
-
-
- char *
- PrologPrompt()
- { if ( !first_prompt_used && first_prompt )
- { first_prompt_used = TRUE;
-
- return first_prompt;
- }
-
- if ( Sinput->position && Sinput->position->linepos == 0 )
- return stringAtom(prompt_atom);
- else
- return "";
- }
-
-
- word
- pl_tab2(term_t stream, term_t n)
- { streamOutput(stream, pl_tab(n)); /* TBD */
- }
-
- /********************************
- * STREAM BASED I/O *
- *********************************/
-
- static bool
- setUnifyStreamNo(term_t stream, int n)
- { atom_t a;
-
- if ( PL_get_atom(stream, &a) )
- { register int i;
-
- for(i = 0; i < maxfiles; i++ )
- { if ( fileTable[i].status != F_CLOSED &&
- fileTable[i].stream_name == a )
- { term_t obj = PL_new_term_ref();
-
- PL_unify_term(obj, PL_FUNCTOR, FUNCTOR_alias1, PL_ATOM, a);
-
- return PL_error(NULL, 0, NULL,
- ERR_PERMISSION, ATOM_open, ATOM_source_sink, obj);
- }
- }
- fileTable[n].stream_name = a;
- succeed;
- }
-
- return unifyStreamNo(stream, n);
- }
-
-
- static const opt_spec open4_options[] =
- { { ATOM_type, OPT_ATOM },
- { ATOM_reposition, OPT_BOOL },
- { ATOM_alias, OPT_ATOM },
- { ATOM_eof_action, OPT_ATOM },
- { ATOM_close_on_abort, OPT_BOOL },
- { ATOM_buffer, OPT_ATOM },
- { NULL_ATOM, 0 }
- };
-
-
- word
- pl_open4(term_t file, term_t mode,
- term_t stream, term_t options)
- { int m = -1;
- atom_t mname;
- atom_t type = ATOM_text;
- bool reposition = FALSE;
- atom_t alias = NULL_ATOM;
- atom_t eof_action = ATOM_eof_code;
- atom_t buffer = ATOM_full;
- bool close_on_abort = TRUE;
- int flags = OPEN_OPEN;
-
- if ( !scan_options(options, 0, ATOM_stream_option, open4_options,
- &type, &reposition, &alias, &eof_action,
- &close_on_abort, &buffer) )
- fail;
-
- if ( alias )
- TRY(PL_unify_atom(stream, alias));
- if ( type == ATOM_text )
- flags |= OPEN_TEXT;
-
- if ( PL_get_atom(mode, &mname) )
- { if ( mname == ATOM_write )
- m = F_WRITE;
- else if ( mname == ATOM_append )
- m = F_APPEND;
- else if ( mname == ATOM_update )
- m = F_WRNOTRUNC;
- else if ( mname == ATOM_read )
- m = F_READ;
-
- if ( m < 0 )
- return PL_error("open", 4, NULL, ERR_DOMAIN, ATOM_io_mode, mode);
- } else
- { return PL_error("open", 4, NULL, ERR_TYPE, ATOM_atom, mode);
- }
-
- if ( m == F_READ )
- { int in = Input;
-
- if ( openStream(file, m, flags) )
- { if ( setUnifyStreamNo(stream, Input) )
- { IOSTREAM *s = fileTable[Input].stream;
-
- if ( eof_action != ATOM_eof_code )
- { if ( eof_action == ATOM_reset )
- s->flags |= SIO_NOFEOF;
- else if ( eof_action == ATOM_error )
- s->flags |= SIO_FEOF2ERR;
- }
- if ( !close_on_abort )
- s->flags |= SIO_NOCLOSE;
- Input = in;
- pushInputContext();
- succeed;
- }
- closeStream(Input);
- Input = in;
-
- fail;
- }
- Input = in;
- fail;
- } else
- { int out = Output;
- if ( openStream(file, m, flags) )
- { if ( setUnifyStreamNo(stream, Output) )
- { IOSTREAM *s = fileTable[Output].stream;
-
- if ( !close_on_abort )
- s->flags |= SIO_NOCLOSE;
- if ( buffer != ATOM_full )
- { s->flags &= ~SIO_FBUF;
- if ( buffer == ATOM_line )
- s->flags |= SIO_LBUF;
- if ( buffer == ATOM_false )
- s->flags |= SIO_NBUF;
- }
-
- Output = out;
- succeed;
- }
- closeStream(Output);
- Output = out;
-
- fail;
- }
- Output = out;
- fail;
- }
- }
-
-
- word
- pl_open(term_t file, term_t mode, term_t stream)
- { term_t n = PL_new_term_ref();
- PL_put_nil(n);
-
- return pl_open4(file, mode, stream, n);
- }
-
-
- /*******************************
- * NULL-STREAM *
- *******************************/
-
- static int
- Swrite_null(void *handle, char *buf, int size)
- { return size;
- }
-
-
- static int
- Sread_null(void *handle, char *buf, int size)
- { return 0;
- }
-
-
- static long
- Sseek_null(void *handle, long offset, int whence)
- { switch(whence)
- { case SIO_SEEK_SET:
- return offset;
- case SIO_SEEK_CUR:
- case SIO_SEEK_END:
- default:
- return -1;
- }
- }
-
-
- static int
- Sclose_null(void *handle)
- { return 0;
- }
-
-
- static IOFUNCTIONS nullFunctions =
- { Sread_null,
- Swrite_null,
- Sseek_null,
- Sclose_null
- };
-
-
- word
- pl_open_null_stream(term_t stream)
- { int sflags = SIO_NBUF|SIO_RECORDPOS;
- IOSTREAM *s = Snew((void *)NULL, sflags, &nullFunctions);
-
- return PL_open_stream(stream, s);
- }
-
-
- int
- streamNo(term_t spec, int mode)
- { int n = -1;
-
- if ( !PL_get_integer(spec, &n) )
- { atom_t name;
-
- if ( PL_get_atom(spec, &name) )
- { if ( name == ATOM_user )
- n = (mode == F_READ ? 0 : 1);
- else if ( name == ATOM_user_input )
- n = 0;
- else if ( name == ATOM_user_output )
- n = 1;
- else if ( name == ATOM_user_error )
- n = 2;
- else
- { int i;
-
- for(i = 3; i < maxfiles; i++)
- { if ( fileTable[i].stream_name == name )
- { n = i;
- break;
- }
- }
- }
- }
- }
-
- if ( n < 0 || n >= maxfiles )
- { PL_error(NULL, 0, NULL, ERR_DOMAIN, ATOM_stream_or_alias, spec);
- return -1;
- }
- if ( fileTable[n].status == F_CLOSED )
- { PL_error(NULL, 0, "closed", ERR_EXISTENCE, ATOM_stream, spec);
- return -1;
- }
-
- switch(mode)
- { case F_ANY:
- return n;
- case F_READ:
- if ( fileTable[n].status != F_READ )
- { PL_error(NULL, 0, NULL, ERR_PERMISSION,
- ATOM_input, ATOM_stream, spec);
- return -1;
- }
- break;
- case F_APPEND:
- case F_WRNOTRUNC:
- case F_WRITE:
- if ( fileTable[n].status != F_WRITE )
- { PL_error(NULL, 0, NULL, ERR_PERMISSION,
- ATOM_output, ATOM_stream, spec);
- return -1;
- }
- }
-
- return n;
- }
-
-
- word
- pl_close(term_t stream)
- { int n;
- int isread;
-
- if ( (n = streamNo(stream, F_ANY)) < 0 )
- fail;
- isread = (fileTable[n].status == F_READ);
-
- TRY( closeStream(n) );
- if ( isread )
- popInputContext();
-
- if ( n == Output )
- Output = 1;
- if ( n == Input )
- Input = 0;
-
- succeed;
- }
-
- word
- pl_current_stream(term_t file, term_t mode,
- term_t stream, word h)
- { int n;
-
- switch( ForeignControl(h) )
- { case FRG_FIRST_CALL:
- n = 3;
- break;
- case FRG_REDO:
- n = ForeignContextInt(h);
- break;
- case FRG_CUTTED:
- default:
- succeed;
- }
-
- for( ; n < maxfiles; n++)
- { fid_t fid = PL_open_foreign_frame();
-
- if ( unifyStreamName(file, n) == FALSE ||
- unifyStreamMode(mode, n) == FALSE ||
- unifyStreamNo(stream, n) == FALSE )
- { PL_discard_foreign_frame(fid);
- continue;
- }
-
- PL_close_foreign_frame(fid);
-
- if ( ++n < maxfiles )
- ForeignRedoInt(n);
-
- succeed;
- }
-
- fail;
- }
-
-
- word
- pl_flush_output(term_t stream)
- { int n;
-
- if ( (n = streamNo(stream, F_WRITE)) < 0 )
- fail;
- TRYPIPE(n, ATOM_write, Sflush(fileTable[n].stream), fail);
-
- succeed;
- }
-
-
- static IOSTREAM *
- ioStreamWithPosition(term_t stream)
- { int n;
- IOSTREAM *s;
-
- if ( (n = streamNo(stream, F_ANY)) < 0 )
- fail;
- s = fileTable[n].stream;
- if ( !s->position )
- { PL_error(NULL, 0, NULL, ERR_PERMISSION, /* non-ISO */
- ATOM_property, ATOM_position, stream);
- return NULL;
- }
-
- return s;
- }
-
-
- word
- pl_stream_position(term_t stream, term_t old, term_t new)
- { IOSTREAM *s;
- long oldcharno, charno, linepos, lineno;
- term_t a = PL_new_term_ref();
- functor_t f;
-
- if ( !(s = ioStreamWithPosition(stream)) )
- fail;
-
- charno = s->position->charno;
- lineno = s->position->lineno;
- linepos = s->position->linepos;
- oldcharno = charno;
-
- if ( !PL_unify_functor(old, FUNCTOR_stream_position3) ||
- !PL_get_arg(1, old, a) ||
- !PL_unify_integer(a, charno) ||
- !PL_get_arg(2, old, a) ||
- !PL_unify_integer(a, lineno) ||
- !PL_get_arg(3, old, a) ||
- !PL_unify_integer(a, linepos) )
- fail;
-
- if ( !(PL_get_functor(new, &f) && f == FUNCTOR_stream_position3) ||
- !PL_get_arg(1, new, a) ||
- !PL_get_long(a, &charno) ||
- !PL_get_arg(2, new, a) ||
- !PL_get_long(a, &lineno) ||
- !PL_get_arg(3, new, a) ||
- !PL_get_long(a, &linepos) )
- return PL_error("stream_position", 3, NULL,
- ERR_DOMAIN, ATOM_stream_position, new);
-
- if ( charno != oldcharno && Sseek(s, charno, 0) < 0 )
- return PL_error("stream_position", 3, OsError(),
- ERR_STREAM_OP, ATOM_position, stream);
-
- s->position->charno = charno;
- s->position->lineno = lineno;
- s->position->linepos = linepos;
-
- succeed;
- }
-
-
- word
- pl_set_input(term_t stream)
- { int n;
-
- if ( (n = streamNo(stream, F_READ)) < 0 )
- fail;
-
- Input = n;
- succeed;
- }
-
-
- word
- pl_set_output(term_t stream)
- { int n;
-
- if ( (n = streamNo(stream, F_WRITE)) < 0 )
- fail;
-
- Output = n;
- succeed;
- }
-
-
- word
- pl_current_input(term_t stream)
- { return unifyStreamNo(stream, Input);
- }
-
-
- word
- pl_current_output(term_t stream)
- { return unifyStreamNo(stream, Output);
- }
-
- word
- pl_character_count(term_t stream, term_t count)
- { IOSTREAM *s = ioStreamWithPosition(stream);
-
- if ( s )
- return PL_unify_integer(count, s->position->charno);
-
- fail;
- }
-
- word
- pl_line_count(term_t stream, term_t count)
- { IOSTREAM *s = ioStreamWithPosition(stream);
-
- if ( s )
- return PL_unify_integer(count, s->position->lineno);
-
- fail;
- }
-
- word
- pl_line_position(term_t stream, term_t count)
- { IOSTREAM *s = ioStreamWithPosition(stream);
-
- if ( s )
- return PL_unify_integer(count, s->position->linepos);
-
- fail;
- }
-
-
- word
- pl_source_location(term_t file, term_t line)
- { char *s;
- char tmp[MAXPATHLEN];
-
- if ( ReadingSource &&
- (s = AbsoluteFile(stringAtom(source_file_name), tmp)) &&
- PL_unify_atom_chars(file, s) &&
- PL_unify_integer(line, source_line_no) )
- succeed;
-
- fail;
- }
-
-
- word
- pl_at_end_of_stream1(term_t stream)
- { int n;
-
- if ( (n = streamNo(stream, F_READ)) < 0 )
- fail;
-
- return Sfeof(fileTable[n].stream) ? TRUE : FALSE;
- }
-
-
- word
- pl_at_end_of_stream0()
- { IOSTREAM *s = fileTable[Input].stream;
-
- if ( !s || Sfeof(s) )
- succeed;
-
- fail;
- }
-
-
- word
- pl_peek_byte2(term_t stream, term_t chr)
- { int n;
- IOSTREAM *s;
- IOPOS pos;
- int c;
-
- if ( (n = streamNo(stream, F_READ)) < 0 ||
- !(s = fileTable[n].stream) )
- fail;
-
- pos = s->posbuf;
- c = Sgetc(s);
- Sungetc(c, s);
- s->posbuf = pos;
-
- return PL_unify_integer(chr, c);
- }
-
-
- word
- pl_peek_byte1(term_t chr)
- { IOSTREAM *s;
- IOPOS pos;
- int c;
-
- if ( !(s = fileTable[Input].stream) )
- fail;
-
- pos = s->posbuf;
- c = Sgetc(s);
- Sungetc(c, s);
- s->posbuf = pos;
-
- return PL_unify_integer(chr, c);
- }
-
-
- /********************************
- * FILES *
- *********************************/
-
- bool
- unifyTime(term_t t, long time)
- { return PL_unify_float(t, (double)time);
- }
-
-
- char *
- PL_get_filename(term_t n, char *buf, unsigned int size)
- { char *name;
- char tmp[MAXPATHLEN];
-
- if ( !PL_get_chars(n, &name, CVT_ALL) )
- { PL_error(NULL, 0, NULL, ERR_TYPE, ATOM_atom, n);
- return NULL;
- }
- if ( !(name = ExpandOneFile(name, tmp)) )
- return NULL;
-
- if ( buf )
- { if ( strlen(name) < size )
- { strcpy(buf, name);
- return buf;
- }
-
- PL_error(NULL, 0, NULL, ERR_REPRESENTATION,
- ATOM_max_path_length);
- return NULL;
- } else
- return buffer_string(name, 0);
- }
-
-
- word
- pl_time_file(term_t name, term_t t)
- { char *fn;
-
- if ( (fn = PL_get_filename(name, NULL, 0)) )
- { long time;
-
- if ( (time = LastModifiedFile(fn)) == -1 )
- fail;
-
- return unifyTime(t, time);
- }
-
- fail;
- }
-
-
- word
- pl_size_file(term_t name, term_t len)
- { char *n;
-
- if ( (n = PL_get_filename(name, NULL, 0)) )
- { long size;
-
- if ( (size = SizeFile(n)) < 0 )
- return PL_error("size_file", 2, OsError(), ERR_FILE_OPERATION,
- ATOM_size, ATOM_file, name);
-
- return PL_unify_integer(len, size);
- }
-
- fail;
- }
-
-
- word
- pl_access_file(term_t name, term_t mode)
- { char *n;
- int md;
- atom_t m;
-
- if ( !PL_get_atom(mode, &m) )
- return PL_error("access_file", 2, NULL, ERR_TYPE, ATOM_atom, mode);
- if ( !(n=PL_get_filename(name, NULL, 0)) )
- fail;
-
- if ( m == ATOM_none )
- succeed;
-
- if ( m == ATOM_write || m == ATOM_append )
- md = ACCESS_WRITE;
- else if ( m == ATOM_read )
- md = ACCESS_READ;
- else if ( m == ATOM_execute )
- md = ACCESS_EXECUTE;
- else if ( m == ATOM_exist )
- md = ACCESS_EXIST;
- else
- return PL_error("access_file", 2, NULL, ERR_DOMAIN, ATOM_io_mode, mode);
-
- if ( AccessFile(n, md) )
- succeed;
-
- if ( md == ACCESS_WRITE && !AccessFile(n, ACCESS_EXIST) )
- { char tmp[MAXPATHLEN];
- char *dir = DirName(n, tmp);
-
- if ( dir[0] )
- { if ( !ExistsDirectory(dir) )
- fail;
- }
- if ( AccessFile(dir[0] ? dir : ".", md) )
- succeed;
- }
-
- fail;
- }
-
-
- word
- pl_read_link(term_t file, term_t link, term_t to)
- { char *n, *l, *t;
- char buf[MAXPATHLEN];
-
- if ( !(n = PL_get_filename(file, NULL, 0)) )
- fail;
-
- if ( (l = ReadLink(n, buf)) &&
- PL_unify_atom_chars(link, l) &&
- (t = DeRefLink(n, buf)) &&
- PL_unify_atom_chars(to, t) )
- succeed;
-
- fail;
- }
-
-
- word
- pl_exists_file(term_t name)
- { char *n;
-
- if ( !(n = PL_get_filename(name, NULL, 0)) )
- fail;
-
- return ExistsFile(n);
- }
-
-
- word
- pl_exists_directory(term_t name)
- { char *n;
-
- if ( !(n = PL_get_filename(name, NULL, 0)) )
- fail;
-
- return ExistsDirectory(n);
- }
-
-
- word
- pl_tmp_file(term_t base, term_t name)
- { char *n;
-
- if ( !PL_get_chars(base, &n, CVT_ALL) )
- return PL_error("tmp_file", 2, NULL, ERR_TYPE, ATOM_atom, base);
-
- return PL_unify_atom(name, TemporaryFile(n));
- }
-
-
- word
- pl_delete_file(term_t name)
- { char *n;
-
- if ( !(n = PL_get_filename(name, NULL, 0)) )
- fail;
-
- return RemoveFile(n);
- }
-
-
- word
- pl_same_file(term_t file1, term_t file2)
- { char *n1, *n2;
- char name1[MAXPATHLEN];
-
- if ( (n1 = PL_get_filename(file1, name1, sizeof(name1))) &&
- (n2 = PL_get_filename(file2, NULL, 0)) )
- return SameFile(name1, n2);
-
- fail;
- }
-
-
- word
- pl_rename_file(term_t old, term_t new)
- { char *o, *n;
- char ostore[MAXPATHLEN];
-
- if ( (o = PL_get_filename(old, ostore, sizeof(ostore))) &&
- (n = PL_get_filename(new, NULL, 0)) )
- { if ( RenameFile(ostore, n) )
- succeed;
-
- if ( fileerrors )
- return PL_error("rename_file", 2, OsError(), ERR_FILE_OPERATION,
- ATOM_rename, ATOM_file, old);
- fail;
- }
-
- fail;
- }
-
-
- word
- pl_fileerrors(term_t old, term_t new)
- { return setBoolean(&fileerrors, "fileerrors", old, new);
- }
-
-
- word
- pl_absolute_file_name(term_t name, term_t expanded)
- { char *n;
- char tmp[MAXPATHLEN];
-
- if ( (n = PL_get_filename(name, NULL, 0)) &&
- (n = AbsoluteFile(n, tmp)) )
- return PL_unify_atom_chars(expanded, n);
-
- fail;
- }
-
-
- word
- pl_is_absolute_file_name(term_t name)
- { char *n;
-
- if ( (n = PL_get_filename(name, NULL, 0)) &&
- IsAbsolutePath(n) )
- succeed;
-
- fail;
- }
-
-
- word
- pl_chdir(term_t dir)
- { char *n;
-
- if ( (n = PL_get_filename(dir, NULL, 0)) )
- { if ( ChDir(n) )
- succeed;
-
- if ( fileerrors )
- return PL_error("chdir", 1, NULL, ERR_FILE_OPERATION,
- ATOM_chdir, ATOM_directory, dir);
- fail;
- }
-
- fail;
- }
-
-
- word
- pl_file_base_name(term_t f, term_t b)
- { char *n;
-
- if ( !PL_get_chars(f, &n, CVT_ALL) )
- return PL_error("file_base_name", 2, NULL, ERR_TYPE, ATOM_atom, f);
-
- return PL_unify_atom_chars(b, BaseName(n));
- }
-
-
- word
- pl_file_dir_name(term_t f, term_t b)
- { char *n;
- char tmp[MAXPATHLEN];
-
- if ( !PL_get_chars(f, &n, CVT_ALL) )
- return PL_error("file_dir_name", 2, NULL, ERR_TYPE, ATOM_atom, f);
-
- return PL_unify_atom_chars(b, DirName(n, tmp));
- }
-
-
- static int
- has_extension(const char *name, const char *ext)
- { const char *s = name + strlen(name);
-
- if ( ext[0] == EOS )
- succeed;
-
- while(*s != '.' && *s != '/' && s > name)
- s--;
- if ( *s == '.' && s > name && s[-1] != '/' )
- { if ( ext[0] == '.' )
- ext++;
- if ( trueFeature(FILE_CASE_FEATURE) )
- return strcmp(&s[1], ext) == 0;
- else
- return stricmp(&s[1], ext) == 0;
- }
-
- fail;
- }
-
-
- word
- pl_file_name_extension(term_t base, term_t ext, term_t full)
- { char *b = NULL, *e = NULL, *f;
- char buf[MAXPATHLEN];
-
- if ( PL_get_chars(full, &f, CVT_ALL) )
- { char *s = f + strlen(f); /* ?base, ?ext, +full */
-
- while(*s != '.' && *s != '/' && s > f)
- s--;
- if ( *s == '.' )
- { if ( PL_get_chars(ext, &e, CVT_ALL) )
- { if ( e[0] == '.' )
- e++;
- if ( trueFeature(FILE_CASE_FEATURE) )
- { TRY(strcmp(&s[1], e) == 0);
- } else
- { TRY(stricmp(&s[1], e) == 0);
- }
- } else
- { TRY(PL_unify_atom_chars(ext, &s[1]));
- }
- if ( s-f > MAXPATHLEN )
- { maxpath:
- return PL_error("file_name_extension", 3, NULL, ERR_REPRESENTATION,
- ATOM_max_path_length);
- }
- strncpy(buf, f, s-f);
- buf[s-f] = EOS;
-
- return PL_unify_atom_chars(base, buf);
- }
- if ( PL_unify_atom_chars(ext, "") &&
- PL_unify(full, base) )
- PL_succeed;
-
- PL_fail;
- } else if ( !PL_is_variable(full) )
- return PL_error("file_name_extension", 3, NULL, ERR_TYPE,
- ATOM_atom, full);
-
- if ( PL_get_chars(base, &b, CVT_ALL|BUF_RING) &&
- PL_get_chars(ext, &e, CVT_ALL) )
- { char *s;
-
- if ( e[0] == '.' ) /* +Base, +Extension, -full */
- e++;
- if ( has_extension(b, e) )
- return PL_unify(base, full);
- if ( strlen(b) + 1 + strlen(e) + 1 > MAXPATHLEN )
- goto maxpath;
- strcpy(buf, b);
- s = buf + strlen(buf);
- *s++ = '.';
- strcpy(s, e);
-
- return PL_unify_atom_chars(full, buf);
- }
-
- if ( !b )
- return PL_error("file_name_extension", 3, NULL, ERR_TYPE,
- ATOM_atom, base);
- return PL_error("file_name_extension", 3, NULL, ERR_TYPE,
- ATOM_atom, ext);
- }
-
-
- word
- pl_prolog_to_os_filename(term_t pl, term_t os)
- {
- #ifdef O_XOS
- char *n;
- char buf[MAXPATHLEN];
-
- if ( PL_get_chars(pl, &n, CVT_ALL) )
- { _xos_os_filename(n, buf);
- return PL_unify_atom_chars(os, buf);
- }
- if ( !PL_is_variable(pl) )
- return PL_error("prolog_to_os_filename", 2, NULL, ERR_TYPE,
- ATOM_atom, pl);
-
- if ( PL_get_chars(os, &n, CVT_ALL) )
- { _xos_canonical_filename(n, buf);
- return PL_unify_atom_chars(pl, buf);
- }
-
- return PL_error("prolog_to_os_filename", 2, NULL, ERR_TYPE,
- ATOM_atom, os);
- #else /*O_XOS*/
- return PL_unify(pl, os);
- #endif /*O_XOS*/
- }
-
-
- #if defined(O_XOS) && defined(__WIN32__)
- word
- pl_make_fat_filemap(term_t dir)
- { char *n;
-
- if ( (n = PL_get_filename(dir, NULL, 0)) )
- { if ( _xos_make_filemap(n) == 0 )
- succeed;
-
- if ( fileerrors )
- return PL_error("make_fat_filemap", 1, NULL, ERR_FILE_OPERATION,
- ATOM_write, ATOM_file, dir);
-
- fail;
- }
-
- fail;
- }
- #endif
-